package com.turing.common.handler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.List;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.turing.common.exception.BusinessException;
import com.turing.common.exception.ParameterInvalidException;
import com.turing.common.exception.ServiceException;
import com.turing.common.response.ResponseCode;
import com.turing.common.response.ResponseMessage;
import com.turing.common.response.ResponseVO;
import com.turing.common.util.Log;
import com.turing.common.util.ResponseUtil;
import com.turing.common.util.Tools;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = IllegalArgumentException.class)
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO<String> handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        Log.error("Log error IllegalArgumentException,requestURI is {},", request.getRequestURI(), e);
        return ResponseVO.<String>builder().status(0).code("400").message(String.format("Parameter %s is Illegal! Please check your parameter and try again!", e.getMessage())).build();
    }

    @ExceptionHandler(ParameterInvalidException.class)
    public ResponseVO<String> handleParameterInvalidException(HttpServletRequest request, ParameterInvalidException e) {
        Log.error("ParameterInvalidException,requestURI is {}, message is {}", request.getRequestURI(), e.getMessage());
        return ResponseVO.<String>builder().status(0).code("203").message(e.getMessage()).build();
    }

    @ExceptionHandler(BindException.class)
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO<String> handleBindException(HttpServletRequest request, BindException e) {
        Log.error("BindException,requestURI is {}, message is {}", request.getRequestURI(), e.getMessage());
        return ResponseVO.<String>builder().status(0).code("203").message(ResponseMessage.PARAMS_REQUIRED).build();
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseVO<Object> methodArgumentNotValidExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
        Log.error("MethodArgumentNotValidException,requestURI is {}, message is {}", request.getRequestURI(), e.getMessage());
        return ResponseVO.builder().status(0).code(ResponseCode.PARAMS_REQUIRED).message(convertObjectErrors(e.getBindingResult().getAllErrors())).build();
    }

    /**
     * 转换错误信息
     *
     * @param objectErrors 错误信息数组
     * @return java.lang.String
     * @author lcy
     * @date 2021/5/10 10:34
     **/
    private static String convertObjectErrors(List<ObjectError> objectErrors) {
        if (Tools.isNotEmpty(objectErrors)) {
            StringBuilder stringBuilder = new StringBuilder();
            //转成字符串
            objectErrors.forEach(objectError -> {
                String errMsg = objectError.getDefaultMessage();
                if (Tools.isNotEmpty(errMsg)) {
                    stringBuilder.append(errMsg).append('\n');
                }
            });
            return stringBuilder.toString();
        }

        return "";
    }

    @ExceptionHandler(value = SQLException.class)
    public ResponseVO<Object> sqlExceptionHandler(HttpServletRequest request, SQLException e) {
        Log.error("sql exception,requestURI is {}, message is {}", request.getRequestURI(), e);
        return ResponseUtil.failed(ResponseCode.PARAMS_REQUIRED, ResponseMessage.PARAMS_REQUIRED);
    }

    @ExceptionHandler(value = DataIntegrityViolationException.class)
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO<Object> dataIntegrityViolationExceptionHandler(HttpServletRequest request, DataIntegrityViolationException e) {
        Log.error("data integrity violation exception,requestURI is {}, message is {}", request.getRequestURI(), e);
        return ResponseUtil.failed(ResponseCode.PARAMS_REQUIRED, ResponseMessage.PARAMS_REQUIRED);
    }

    @ExceptionHandler(value = ServletException.class)
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO<Object> servletExceptionHandler(HttpServletRequest request, ServletException e) {
        Log.error("servlet exception, requestURI is {},message is {}", request.getRequestURI(), e.getMessage());
        return ResponseUtil.failed("400", e.getMessage());
    }

    /**
     * 自定义业务异常
     *
     * @param request           请求对象
     * @param businessException 异常信息
     * @author lcy
     * @date 2019/10/26 9:44
     **/
    @ExceptionHandler({BusinessException.class})
    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseVO<Object> businessException(HttpServletRequest request, BusinessException businessException) {
        Log.error("BusinessException requestURI is {},message is {} ", request.getRequestURI(), businessException.getMessage());
        return ResponseUtil.failed(businessException.getCode(), businessException.getMessage());
    }

    /**
     * 自定义业务异常
     *
     * @param request          请求对象
     * @param serviceException 异常信息
     * @author lcy
     * @date 2019/10/26 9:44
     **/
    @ExceptionHandler({ServiceException.class})
    //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseVO<Object> serviceException(HttpServletRequest request, ServiceException serviceException) {
        Log.error("ServiceException requestURI is {},message is {} ", request.getRequestURI(), serviceException.getMessage());
        return ResponseUtil.failed(serviceException.getCode(), serviceException.getMessage());
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseVO<String> defaultExceptionHandler(HttpServletRequest request, Exception e) {
        Log.error("requestURI:{} ", request.getRequestURI(), e);
        return ResponseUtil.error();
    }

}
